﻿using System;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO.Packaging; // PackageStore
using System.Windows.Documents;
using System.Windows.Xps;
using System.Windows.Xps.Packaging;

using C4Tools; // C4Manager, C4Movie, etc.

using System.Collections.ObjectModel;

namespace C4Tools.ML2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        AppState appState;
        AppStateManager<AppState> stateManager;

        C4Manager c4m;
        List<C4Movie> foundMovies;
        XmlReaderSettings readerSettings = new XmlReaderSettings
        {
            ProhibitDtd = true
        };

        public MainWindow()
        {
            InitializeComponent();
            stateManager = new AppStateManager<AppState>("MovieLister2");
            appState = stateManager.GetState();

            this.textBox1.Text = appState.LastControllerIp;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            TryConnect();
        }

        void TryConnect()
        {
            var ipAddress = this.textBox1.Text.Trim();
            if (String.IsNullOrEmpty(ipAddress)) return;
            this.button1.IsEnabled = false;
            c4m = new C4Manager(ipAddress);
            if (c4m.IsConnected)
            {
                appState.LastControllerIp = ipAddress;
                stateManager.StoreState(appState);
                // get movies
                var cursor = this.Cursor;
                this.Cursor = Cursors.Wait;
                foundMovies = c4m.GetDiscChangerMovies();
                if (foundMovies.Count > 0)
                {
                    BuildDocument();
                }
                this.Cursor = cursor;
            }
        }


        void BuildDocument()
        {
            var docBuilder = new DocumentBuilder(this, foundMovies);
            HookupEvents(docBuilder);
            docBuilder.Start(); // async
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            TryConnect();
        }

        #region Event handling and management
        private void HookupEvents(IProgressWorker operation)
        {
            operation.StageChanged         += new EventHandler(operation_StageChanged);
            operation.ProgressChanged      += new EventHandler(operation_ProgressChanged);
            operation.ProgressTotalChanged += new EventHandler(operation_TotalChanged);
            operation.Complete             += new EventHandler(operation_Complete);
        }

        void operation_StageChanged(object sender, EventArgs e)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                // a thread other than the UI thread
                 this.Dispatcher.BeginInvoke(new Action(()=> { operation_StageChanged(sender, e);}));
            }
            else
            {
                var pw = (sender as IProgressWorker);
                this.labelStage.Content = pw.Stage;
                this.labelProgress.Content = "";
                if (pw.Stage.EndsWith("..."))
                {
                    this.progressBar1.IsIndeterminate = true;
                }
            }
        }

        void operation_ProgressChanged(object sender, EventArgs e)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                // a thread other than the UI thread
                this.Dispatcher.BeginInvoke(new Action(()=> { operation_ProgressChanged(sender, e);}));
            }
            else
            {
                var pw = (sender as IProgressWorker);
                this.progressBar1.Value = pw.Current;
                this.labelProgress.Content = pw.Current + " / " + pw.Total;
            }
        }


        void operation_TotalChanged(object sender, EventArgs e)
        {
            if (!this.Dispatcher.CheckAccess())
            {
                // a thread other than the UI thread
                this.Dispatcher.BeginInvoke(new Action(()=> { operation_TotalChanged(sender, e);}));
            }
            else
            {
                var pw = (sender as IProgressWorker);
                this.progressBar1.Maximum = pw.Total;
                this.labelProgress.Content = pw.Current + " / " + pw.Total;
            }
        }


        void operation_Complete(object sender, EventArgs e)
        {
            var docBuilder = (sender as DocumentBuilder);
            if (docBuilder != null)
            {
                this.labelProgress.Visibility = Visibility.Hidden;
                this.labelStage.Content = "Preparing the document...";
                System.Threading.Thread.Sleep(550);
                ShowPrintPreview(docBuilder.DocStream);
                this.Cursor = Cursors.Arrow;
                this.labelStage.Content = "Done.";
                this.Close();
                return;
            }
        }
        #endregion


        private string previewWindowXamlTemplate =
            @"<Window
                xmlns                 ='http://schemas.microsoft.com/netfx/2007/xaml/presentation'
                xmlns:x               ='http://schemas.microsoft.com/winfx/2006/xaml'
                Title                 ='Printable Movie List - click the printer icon to print'
                Height                ='@@HEIGHT'
                Width                 ='@@WIDTH'
                Icon                  ='/ML2;component/Img/MovieLister.ico'
                >
                <DocumentViewer Name='dv1'/>
             </Window>";

        private void ShowPrintPreview(Stream docStream)
        {
            int width = 520; // width of preview window on screen
            string xaml = previewWindowXamlTemplate;
            xaml = xaml.Replace("@@WIDTH", width.ToString());
            int height = (int)(420 * width / 300);
            xaml = xaml.Replace("@@HEIGHT", height.ToString());

            using (var reader = new System.Xml.XmlTextReader(new StringReader(xaml)))
            {
                Window preview = System.Windows.Markup.XamlReader.Load(reader) as Window;

                using (var package = System.IO.Packaging.Package.Open(docStream, FileMode.Open, FileAccess.Read))
                {
                    string fakeUriString = "anything://i-dont-care.xps";
                    Uri packageUri = new Uri(fakeUriString);
                    PackageStore.AddPackage(packageUri, package); // ?? stupid hoops to jump through

                    // CompressionOption is ignored - we are only reading.
                    var doc = new XpsDocument(package, CompressionOption.NotCompressed, fakeUriString);
                    var fds = doc.GetFixedDocumentSequence();
                    var dv1 = LogicalTreeHelper.FindLogicalNode(preview, "dv1") as DocumentViewer;
                    dv1.Document = fds as IDocumentPaginatorSource;

                    // remove the search bar:
                    // use this to get a named control applied from a template
                    ContentControl cc = dv1.Template.FindName("PART_FindToolBarHost", dv1) as ContentControl;
                    if (cc != null)
                        cc.Visibility = Visibility.Collapsed;

                    // // use this to remove the toolbar from the DocumentViewer:
                    // var p = LogicalTreeHelper.GetParent(cc) as Grid;
                    // cc = p.Children[0] as ContentControl;
                    // if (cc != null)
                    // {
                    //     cc.Visibility = Visibility.Collapsed;
                    //      -or-
                    //     p.Children.RemoveAt(0);
                    // }

                    dv1.FitToMaxPagesAcross(1);

                    // hide parent and show the preview window as a dialog
                    this.Visibility = Visibility.Hidden;
                    preview.Owner = this;
                    preview.ShowDialog();

                    PackageStore.RemovePackage(packageUri);
                }

            }
        }

    }

    public sealed class AppState
    {
        public System.DateTime LastRun { get; set; }
        public int Runs { get; set; }
        public String LastControllerIp { get; set; }
    }

}
